package org.artifact.core.plugin.quartz;

import java.util.ArrayList;
import java.util.Date;
import java.util.Map;

import org.artifact.core.lang.IPlugin;
import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.Job;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.ScheduleBuilder;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SimpleScheduleBuilder;
import org.quartz.SimpleTrigger;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.quartz.impl.StdSchedulerFactory;
import org.quartz.impl.matchers.GroupMatcher;

import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;

public class QuartzPlugin implements IPlugin {

	static final Log log = LogFactory.get(QuartzPlugin.class);

	private Scheduler scheduler = null;
	
	

	public QuartzPlugin() {
		try {
			// 加载配置文件
			StdSchedulerFactory factory = new StdSchedulerFactory("quartz.properties");
			factory.initialize();
			
			scheduler = factory.getScheduler();
		} catch (SchedulerException e) {
			if (log.isErrorEnabled())
				log.error("初始化任务调度出错", e);
		}
	}

	/**
	 * 添加调度任务
	 * 
	 * @param triggerKey
	 *            全局唯一调度任务id
	 * @param cron
	 *            调度任务表达式
	 * @param classs
	 *            调度处理类
	 * @param param
	 *            调度任务参数
	 */
	public void addJob(String name, String group, Date startAt, String cron, Class<? extends Job> classs,
			Map<String, Object> param) {
		ScheduleBuilder<CronTrigger> schedBuilder = CronScheduleBuilder.cronSchedule(cron);
		addJob(name, group, startAt, schedBuilder, classs, param);
	}

	/**
	 * 添加调度任务
	 * 
	 * @param name
	 * @param group
	 * @param startAt
	 * @param intervalInMillis
	 *            间隔时间毫秒
	 * @param repeatCount
	 *            执行次数 -1为不限次数
	 * @param classs
	 * @param param
	 */
	public void addJob(String name, String group, Date startAt, int intervalInMillis, int repeatCount,
			Class<? extends Job> classs, Map<String, Object> param) {
		ScheduleBuilder<SimpleTrigger> schedBuilder = SimpleScheduleBuilder.simpleSchedule()
				.withIntervalInMilliseconds(intervalInMillis).withRepeatCount(repeatCount);
		addJob(name, group, startAt, schedBuilder, classs, param);
	}

	/**
	 * 添加调度任务(高度定制)
	 * 
	 * @param triggerKey
	 *            全局唯一调度任务id
	 * @param schedBuilder
	 *            调度任务表达式
	 * @param classs
	 *            调度处理类
	 * @param param
	 *            调度任务参数
	 * 
	 *            ScheduleBuilder常见调度类型 1.CronScheduleBuilder.cronSchedule(cron) //
	 *            轮询时间，表达式 2.SimpleScheduleBuilder.repeatHourlyForever(24) //
	 *            轮询时间，24小时 3.SimpleScheduleBuilder.repeatMinutelyForever(60) //
	 *            轮询时间，60分钟 4.SimpleScheduleBuilder.repeatSecondlyForever(60) //
	 *            轮询时间，60秒 5.SimpleScheduleBuilder.simpleSchedule()
	 *            .withIntervalInSeconds(10) //时间间隔 .withRepeatCount(5)
	 *            //重复次数(将执行6次)
	 */
	public void addJob(String name, String group, Date startAt, ScheduleBuilder<? extends Trigger> schedBuilder,
			Class<? extends Job> classs, Map<String, Object> param) {
		try {
			boolean exists = scheduler.checkExists(TriggerKey.triggerKey(name, group));
			if (exists) {
				if (log.isWarnEnabled())
					log.warn("调度任务已经存在 name = " + name + " group = " + group);
				return;
			}

			JobDetail jobDetail = JobBuilder.newJob(classs).withIdentity(name, group).build();

			if (param != null && !param.isEmpty()) {
				jobDetail.getJobDataMap().putAll(param);
			}

			Trigger trigger = TriggerBuilder.newTrigger().withIdentity(name, group).withSchedule(schedBuilder)
					.startAt(startAt).build();

			scheduler.scheduleJob(jobDetail, trigger);
		} catch (SchedulerException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 修改调度
	 * 
	 * @param name
	 * @param group
	 * @param startAt
	 * @param intervalInMillis
	 * @param repeatCount
	 */
	public void modifyTime(String name, String group, Date startAt, int intervalInMillis, int repeatCount) {
		ScheduleBuilder<SimpleTrigger> schedBuilder = SimpleScheduleBuilder.simpleSchedule()
				.withIntervalInMilliseconds(intervalInMillis).withRepeatCount(repeatCount);
		modifyTime(name, group, startAt, schedBuilder);
	}

	/**
	 * 修改调度
	 * 
	 * @param name
	 * @param group
	 * @param startAt
	 * @param cron
	 */
	public void modifyTime(String name, String group, Date startAt, String cron) {
		ScheduleBuilder<CronTrigger> schedBuilder = CronScheduleBuilder.cronSchedule(cron);
		modifyTime(name, group, startAt, schedBuilder);
	}

	/**
	 * 修改调度
	 * 
	 * @param name
	 * @param group
	 * @param startAt
	 * @param schedBuilder
	 */
	public void modifyTime(String name, String group, Date startAt, ScheduleBuilder<? extends Trigger> schedBuilder) {
		try {
			TriggerKey tk = TriggerKey.triggerKey(name, group);
			Trigger trg = TriggerBuilder.newTrigger().withIdentity(name, group).withSchedule(schedBuilder)
					.startAt(startAt).build();
			scheduler.rescheduleJob(tk, trg);
			log.debug("修改作业触发时间=> [作业名称：" + name + " 作业组：" + group + "] ");
		} catch (SchedulerException e) {
			e.printStackTrace();
			log.error("修改作业触发时间=> [作业名称：" + name + " 作业组：" + group + "]=> [失败]");
		}
	}

	/**
	 * 删除调度任务
	 * 
	 * @param name
	 * @param group
	 */
	public void removeJob(String name, String group) {
		try {
			TriggerKey tk = TriggerKey.triggerKey(name, group);
			scheduler.pauseTrigger(tk);// 停止触发器
			scheduler.unscheduleJob(tk);// 移除触发器
			JobKey jobKey = JobKey.jobKey(name, group);
			scheduler.deleteJob(jobKey);// 删除作业
			log.debug("删除作业=> [作业名称：" + name + " 作业组：" + group + "] ");
		} catch (SchedulerException e) {
			e.printStackTrace();
			log.error("删除作业=> [作业名称：" + name + " 作业组：" + group + "]=> [失败]");
		}
	}

	/**
	 * 删除调度任务
	 * 
	 * @param name
	 * @param group
	 */
	public void removeJob(String group) {
		try {
			GroupMatcher<TriggerKey> triggerKeyMatcher = GroupMatcher.groupEquals(group);
			GroupMatcher<JobKey> jobKeyMatcher = GroupMatcher.groupEquals(group);

			scheduler.pauseTriggers(triggerKeyMatcher);// 停止触发器
			scheduler.unscheduleJobs(new ArrayList<>(scheduler.getTriggerKeys(triggerKeyMatcher)));// 移除触发器
			scheduler.deleteJobs(new ArrayList<>(scheduler.getJobKeys(jobKeyMatcher)));// 删除作业
			log.debug("删除整组作业=> [作业组：" + group + "] ");
		} catch (SchedulerException e) {
			e.printStackTrace();
			log.error("删除整组作业=> [作业组：" + group + "]=> [失败]");
		}
	}

	/**
	 * 暂停调度
	 * 
	 * @param name
	 * @param group
	 */
	public void pauseJob(String name, String group) {
		try {
			JobKey jobKey = JobKey.jobKey(name, group);
			scheduler.pauseJob(jobKey);
			log.debug("暂停作业=> [作业名称：" + name + " 作业组：" + group + "] ");
		} catch (SchedulerException e) {
			e.printStackTrace();
			log.error("暂停作业=> [作业名称：" + name + " 作业组：" + group + "]=> [失败]");
		}
	}

	/**
	 * 暂停调度
	 * 
	 * @param name
	 * @param group
	 */
	public void pauseJob(String group) {
		try {
			GroupMatcher<JobKey> jobKeyMatcher = GroupMatcher.groupEquals(group);
			scheduler.pauseJobs(jobKeyMatcher);
			log.debug("暂停整组作业=> [作业组：" + group + "] ");
		} catch (SchedulerException e) {
			e.printStackTrace();
			log.error("暂停整组作业=> [作业组：" + group + "]=> [失败]");
		}
	}

	/**
	 * 暂停全部
	 * 
	 * @throws SchedulerException
	 */
	public void pauseAllJob() throws SchedulerException {
		try {
			scheduler.pauseAll();
			log.debug("暂停全部作业=>  ");
		} catch (SchedulerException e) {
			e.printStackTrace();
			log.error("暂停全部作业=> [失败]");
		}
	}

	/**
	 * 恢复调度
	 * 
	 * @param name
	 * @param group
	 */
	public void resumeJob(String name, String group) {
		try {
			JobKey jobKey = JobKey.jobKey(name, group);
			scheduler.resumeJob(jobKey);
			log.debug("恢复作业=> [作业名称：" + name + " 作业组：" + group + "] ");
		} catch (SchedulerException e) {
			e.printStackTrace();
			log.error("恢复作业=> [作业名称：" + name + " 作业组：" + group + "]=> [失败]");
		}
	}

	/**
	 * 恢复调度
	 * 
	 * @param name
	 * @param group
	 */
	public void resumeJob(String group) {
		try {
			GroupMatcher<JobKey> jobKeyMatcher = GroupMatcher.groupEquals(group);
			scheduler.resumeJobs(jobKeyMatcher);
			log.debug("恢复整组作业=> 作业组：" + group + "] ");
		} catch (SchedulerException e) {
			e.printStackTrace();
			log.error("恢复整组作业=> [作业组：" + group + "]=> [失败]");
		}
	}

	/**
	 * 恢复全部
	 * 
	 * @throws SchedulerException
	 */
	public void resumeAllJob() throws SchedulerException {
		try {
			scheduler.resumeAll();
			log.debug("恢复全部作业=>  ");
		} catch (SchedulerException e) {
			e.printStackTrace();
			log.error("恢复全部作业=> [失败]");
		}
	}

	@Override
	public boolean start() {
		if (scheduler != null) {
			try {
				scheduler.start();
				return true;
			} catch (SchedulerException e) {
				if (log.isErrorEnabled())
					log.error("任务调度启动出错", e);
			}
		}
		return false;
	}

	@Override
	public boolean stop() {
		try {
			if (scheduler != null && !scheduler.isShutdown()) {
				scheduler.shutdown();
				int i = 1;
				while (!scheduler.isShutdown()) {
					try {
						Thread.sleep(1000);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					log.debug("QuartzPlugin shutdown...{}", i);
					i++;
				}
			}
		} catch (SchedulerException e) {
			if (log.isErrorEnabled())
				log.error("关闭任务调度出错", e);
		}
		return true;
	}

}
